#ifndef __TRAP_IO_H__
#define __TRAP_IO_H__
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/limits.h>
#include <linux/io.h>

#define WORD_INSTRUCTION_LENGTH     (4)
#define STATUS_OK       (0)
#define STATUS_FAIL     (1)

/* MMIO emulation related structures */
typedef struct
{
    void __iomem *  address;                        /* Virtual address being accessed */
    bool            is_store;                       /* 0 = read / 1 = write operation */
    uint8_t         access_size;                    /* Access size being emulated */
    uint64_t        value;                          /* Value read or value to write */
    
    bool            sign_extend_read;               /* Sign-extended, otherwise zero-extended.  */

    uint32_t        regx;                        /* Get register number for the abort operand as */
    struct pt_regs  *regs;
} mmio_op_t;

typedef int emulation_handle_t(mmio_op_t *mmio);

int trap_io_init(emulation_handle_t fn);
void trap_io_deinit(void);

static inline void set_x_reg(struct pt_regs *regs, int reg, u64 val)
{
    pt_regs_write_reg(regs, reg, val);
}

static inline void set_w_reg(struct pt_regs *regs, int reg, u64 val)
{
    pt_regs_write_reg(regs, reg, lower_32_bits(val));
}

static inline u64 get_x_reg(struct pt_regs *regs, int reg)
{
    return pt_regs_read_reg(regs, reg);
}

static inline u32 get_w_reg(struct pt_regs *regs, int reg)
{
    return lower_32_bits(pt_regs_read_reg(regs, reg));
}

int decode_aarch64_insn(uint32_t insn, mmio_op_t *mmio);

void __iomem *find_within_emu_io(phys_addr_t addr);
#endif
